#include "Files.h"
#include "Arduino.h"

Files::Files()
{

}

Files::~Files()
{

}

/*
 * 		PUBLICS
 */

//Insert de gegeven score op de juiste positie in de score lijst
void Files::SetScore(uint16_t score, char* name)
{
	//haal huidige scores op
	char* highscores[10];
	GetHighscores(highscores);

	bool success = false;
	int i;
	for(i = 0; i < 10 && highscores[i] != NULL; i++)
	{
		char currentScore[20];
		strcpy(currentScore, highscores[i]);
		char* splittedScore = strtok(currentScore, " ");
		uint16_t currentScoreHeight = atol(splittedScore);
		//kijk of hier de score op deze positie gezet moet worden
		if(score >= currentScoreHeight)
		{
			char bfr[20];
			createScoreString(score, name, bfr);
			insert(highscores, i, bfr);
			success = true;
			break;
		}
	}
	//als lijst leeg is, insert op positie 1
	if(!success)
	{
		char bfr[20];
		createScoreString(score, name, bfr);
		insert(highscores, i, bfr);
	}
	this->saveHighscores(highscores);
}

//Haalt lijst van scores op uit EEPROM
void Files::GetHighscores(char* result[])
{
	//lees eerste string, zorg dat buffer groot genoeg is voor de maximale string lengte
	//start positie geheugenadres is 100
	char buffer[25];
	int bytesRead = readString(START_ADDR, buffer, 25);

	int i = 0;
	int position = START_ADDR;
	while(bytesRead > 0)
	{
		result[i] = (char*)calloc(1, strlen(buffer) + 1);
		if(result[i] == NULL) continue;
		strcpy(result[i], buffer);
		position += bytesRead;
		bytesRead = readString(position, buffer, 25);
		i++;
	}
	//rest van array NULL maken zodat we er met een for loop doorheen kunnen
	while(i < 10)
	{
		result[i] = (char*)calloc(1, strlen(buffer) + 1);
		i++;
	}
}

/*
 * 		PRIVATES
 */

//Insert waarde in array
void Files::insert(char** highscores, uint8_t index, char* score)
{
	//Schuif bestaande waardes op, en insert de score op de gewenste plaats
	//Alles boven de 9/10e plaats is niet belangrijk.
	for (int i = 9; i > index; i--)
	{
		highscores[i] = highscores[i - 1];
	}
	highscores[index] = score;
}

//Leegt EEPROM geheugen voor de highscores
void Files::clearEeprom()
{
	//6 + spatie + 10 naam = 17 * 10 = 170 + 10x einde string = max 180
	//deze 180 plaatsen opschonen
	for (int i = 100; i <= 280; i++)
	{
		EEPROM.write(i, 0xFF);
	}
}

//Schrijft een array van bytes weg vanaf de gegeven startpositie
void Files::writeBytes(int startAddr, const uint8_t* array, int numBytes)
{
	for (int i = 0; i < numBytes; i++)
	{
		EEPROM.write(startAddr + i, array[i]);
	}
}

//Schrijft een string weg op de gegeven positie
int Files::writeString(int addr, const char* string)
{
	// aantal bytes dat weg worden geschreven
	int numBytes;

	// string inhoud plus de einde string (0x00)
	numBytes = strlen(string) + 1;

	writeBytes(addr, (const uint8_t*)string, numBytes);

	return numBytes;
}

//Leest een string op gegeven adres, en geeft het aantal gelezen karakters terug
int Files::readString(int addr, char* buffer, int bufferSize)
{
	int bytesRead = 0;
	uint8_t ch;

	ch = EEPROM.read(addr + bytesRead);
	buffer[bytesRead] = ch;

	//is karakter de standaard waarde van EEPROM, dan geen waarde gevonden,
	//return 0 karakters gelezen.
	if(ch == 0xFF)
	{
		return 0;
	}

	//lees tot string terminator, of tot buffer vol, of tot einde van EEPROM
	while( (ch != 0x00) && (bytesRead < bufferSize) && ((addr + bytesRead <= 1024)))
	{
		ch = EEPROM.read(addr + bytesRead);
		buffer[bytesRead] = ch;
		//Schuif telkens een byte op
		bytesRead++;
	}
	//controleer of laatste karakter wel een string terminator is
	if ((ch != 0x00) && (bytesRead >= 1))
	{
	    buffer[bytesRead - 1] = 0;
	}

	return bytesRead;
}

//Slaat scores op in EEPROM
void Files::saveHighscores(char** data)
{
	//eerst geheugen leegmaken
	clearEeprom();

	//startpositie
	uint8_t pos = START_ADDR;
	char buffer[18];
	for(int i = 0; i < 10 && data[i] != NULL; i++)
	{
		strcpy(buffer, data[i]);
		pos += writeString(pos, buffer);
	}
}

//Maakt string van naam en score, zoals deze wordt opgeslagen in EEPROM
void Files::createScoreString(uint16_t score, char* name, char* result)
{
	//int to string
	itoa(score, result, 10);
	strcat(result, " ");
	//wanneer naam langer is dan 10 karakters, substring
	if(strlen(name) > 10)
	{
		char substr[10];
		strncpy(substr, name, 10);
		strcat(result, substr);
	}
	else
	{
		strcat(result, name);
	}
}
